/*
-------------------------------------------------

	OGG.cpp

	Dmitriy Kuzmenko (Dgut)

-------------------------------------------------
*/

#include "OGG.h"
#include "File.h"
#include <memory.h>

namespace Autumn
{

OGG::OGG( const char * fileName, bool streamed ) :
	channels	( 0 ),
	rate		( 0 ),
	size		( 0 ),
	data		( 0 )
{
	memset( &file, 0, sizeof( file ) );
	
	FILE * stream = gFile.Open( fileName, "rb" );
	if( !stream )
		return;
	
	ov_callbacks callbacks;
	
	callbacks.read_func = ( size_t ( * )( void *, size_t, size_t, void * ) )fread;
	callbacks.seek_func = ( int ( * )( void *, ogg_int64_t, int ) )
#if defined WIN32
		_fseeki64;
#elif defined IPHONE
		fseeko;
#endif
	callbacks.close_func = ( int ( * )( void * ) )fclose;
	callbacks.tell_func = ( long ( * )( void * ) )ftell;
	
	if( ov_open_callbacks( stream, &file, 0, 0, callbacks ) < 0 )
		return;

	vorbis_comment * comment = ov_comment( &file, -1 );
	vorbis_info * info = ov_info( &file, -1 );

	channels = info->channels;
	rate = info->rate;
	size = ov_pcm_total( &file, -1 ) * 2 * channels;

	if( streamed )
		return;

	data = new char[ size ];

	long total = 0;
	int bitstream;

	while( total != size )
	{
		const long READED = ov_read( &file, data + total, size - total, 0, 2, 1, &bitstream );

		if( READED < 0 )
		{
			ov_clear( &file );
			return;
		}
		else
			total += READED;
	}
}

OGG::~OGG( void )
{
	delete[] data;
	ov_clear( &file );
}

const long OGG::Read( char * buffer, long size )
{
	long total = 0;
	int bitstream;

	while( total != size )
	{
		const long READED = ov_read( &file, buffer + total, size - total, 0, 2, 1, &bitstream );

		if( READED <= 0 )
			return total;
		else
			total += READED;
	}

	return total;
}

void OGG::Rewind( void )
{
	ov_pcm_seek( &file, 0 );
}

}	// namespace Autumn